"use strict";
import React, { useState, useEffect, useRef } from "react";
import { Button, Tooltip, Divider } from "antd";
import Gmodal from "@/component/modal";
import {
  FolderOpenOutlined,
  DownloadOutlined,
  EyeOutlined,
  PlaySquareOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
  AlignCenterOutlined,
  UndoOutlined,
  RedoOutlined,
  SyncOutlined,
} from "@ant-design/icons";
import Highlight from "@/component/highlight";
import X2JS from "x2js";
import styles from "./index.less";

/*
 * 组件注释
 * create by wuqiong
 * creation time 2022/03/11
 * 顶部功能栏
 * */

const getTitle = text => (
  <span style={{ color: "#303133", fontSize: 12 }}>{text}</span>
);
const downStyle = { display: "block", fontSize: 12 };
const tooltipColor = "#fff";
const Index = props => {
  const {
    bpmnModeler,
    events = ["element.click"],
    simulation = true,
    createNewDiagram,
  } = props;
  const [defaultZoom, setDefaultZoom] = useState(1);
  const [recoverable, setRecoverable] = useState(false);
  const [revocable, setRevocable] = useState(false);
  const [previewModelVisible, setPreviewModelVisible] = useState(false);
  const [simulationStatus, setSimulationStatus] = useState(false);
  const [previewResult, setPreviewResult] = useState("");
  const [previewType, setPreviewType] = useState("xml");
  const refFile = useRef(null);

  // 第一模块 上传、下载、预览、模拟
  const importLocalFile = el => {
    const file = refFile.current.files[0];
    const reader = new FileReader();
    reader.readAsText(file);
    reader.onload = function (e) {
      let xmlStr = e.target.result;
      createNewDiagram(xmlStr);
      el.target.value = null;
    };
  };
  const downloadProcessAsXml = () => downloadProcess("xml");
  const downloadProcessAsSvg = () => downloadProcess("svg");
  const downloadProcessAsBpmn = () => downloadProcess("bpmn");
  const downloadProcess = async (type, name) => {
    try {
      // 按需要类型创建文件并下载
      if (type === "xml" || type === "bpmn") {
        const { err, xml } = await bpmnModeler.saveXML();
        // 读取异常时抛出异常
        if (err) {
          console.error(`[Process Designer Warn ]: ${err.message || err}`);
        }
        let { href, filename } = setEncoded(type.toUpperCase(), name, xml);
        downloadFunc(href, filename);
      } else {
        const { err, svg } = await bpmnModeler.saveSVG();
        // 读取异常时抛出异常
        if (err) {
          return console.error(err);
        }
        let { href, filename } = setEncoded("SVG", name, svg);
        downloadFunc(href, filename);
      }
    } catch (e) {
      console.error(`[Process Designer Warn ]: ${e.message || e}`);
    }
    // 文件下载方法
    function downloadFunc(href, filename) {
      if (href && filename) {
        let a = document.createElement("a");
        a.download = filename; //指定下载的文件名
        a.href = href; //  URL对象
        a.click(); // 模拟点击
        URL.revokeObjectURL(a.href); // 释放URL 对象
      }
    }
  };
  const setEncoded = (type, filename = "diagram", data) => {
    const encodedData = encodeURIComponent(data);
    return {
      filename: `${filename}.${type}`,
      href: `data:application/${
        type === "svg" ? "text/xml" : "bpmn20-xml"
      };charset=UTF-8,${encodedData}`,
      data: data,
    };
  };

  const previewProcessXML = () => {
    bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      setPreviewResult(xml);
      setPreviewType("xml");
      setPreviewModelVisible(true);
    });
  };
  const previewProcessJson = () => {
    const newConvert = new X2JS();
    bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
      const { definitions } = newConvert.xml2js(xml);
      if (definitions) {
        setPreviewResult(JSON.stringify(definitions, null, 4));
      } else {
        setPreviewResult("");
      }
      setPreviewType("json");
      setPreviewModelVisible(true);
    });
  };
  // TODO 不报错但是执行效果也不对
  const processSimulation = () => {
    setSimulationStatus(!simulationStatus);
    simulation && bpmnModeler.get("toggleMode").toggleMode();
  };
  // 第二模块 缩小、放大、重置居中
  const processZoomOut = (zoomStep = 0.1) => {
    let newZoom = Math.floor(defaultZoom * 100 - zoomStep * 100) / 100;
    if (newZoom < 0.2) {
      throw new Error(
        "[Process Designer Warn ]: The zoom ratio cannot be less than 0.2"
      );
    }
    setDefaultZoom(newZoom);
    bpmnModeler.get("canvas").zoom(newZoom);
  };
  const processZoomIn = (zoomStep = 0.1) => {
    let newZoom = Math.floor(defaultZoom * 100 + zoomStep * 100) / 100;
    if (newZoom > 4) {
      throw new Error(
        "[Process Designer Warn ]: The zoom ratio cannot be greater than 4"
      );
    }
    setDefaultZoom(newZoom);
    bpmnModeler.get("canvas").zoom(newZoom);
  };
  const processReZoom = () => {
    setDefaultZoom(1);
    bpmnModeler.get("canvas").zoom("fit-viewport", "auto");
  };

  // 第三模块 撤销、恢复、重置清空
  const processUndo = () => {
    bpmnModeler.get("commandStack").undo();
  };
  const processRedo = () => {
    bpmnModeler.get("commandStack").redo();
  };
  const processRestart = () => {
    setRecoverable(false);
    setRevocable(false);
    createNewDiagram(null);
  };

  // 事件注册监听
  const initModelListeners = () => {
    const EventBus = bpmnModeler.get("eventBus");

    // 注册需要的监听事件, 将. 替换为 - , 避免解析异常
    events.forEach(event => {
      EventBus.on(event, function (eventObj) {
        let eventName = event.replace(/\./g, "-");
        let element = eventObj ? eventObj.element : null;
        props?.eventListeners?.(eventName, element, eventObj);
      });
    });
    // 监听图形改变返回xml
    EventBus.on("commandStack.changed", async event => {
      try {
        const recoverable = bpmnModeler.get("commandStack").canRedo();
        const revocable = bpmnModeler.get("commandStack").canUndo();
        setRecoverable(recoverable);
        setRevocable(revocable);
        let { xml } = await bpmnModeler.saveXML({ format: true });
        props?.commandStackChanged?.(event);
        props?.input?.(xml);
        props?.change?.(xml);
      } catch (e) {
        console.error(`[Process Designer Warn]: ${e.message || e}`);
      }
    });
    // 监听视图缩放变化
    bpmnModeler.on("canvas.viewbox.changed", ({ viewbox }) => {
      props?.canvasViewboxChanged?.({ viewbox });
      const { scale } = viewbox;
      setDefaultZoom(Math.floor(scale * 100) / 100);
    });
  };

  useEffect(() => {
    // if (bpmnModeler) return;
    initModelListeners();
  }, []);

  return (
    <div className={styles.zoom}>
      <Button.Group>
        <Tooltip title={getTitle("打开文件")} color={tooltipColor}>
          <Button
            onClick={() => refFile.current.click()}
            icon={<FolderOpenOutlined />}
            type={"primary"}>
            打开文件
          </Button>
        </Tooltip>
        <Divider className={styles.divider} type="vertical" />
        <Tooltip
          color={tooltipColor}
          title={
            <div>
              <Button
                onClick={() => downloadProcessAsXml()}
                style={downStyle}
                type={"link"}>
                下载为XML文件
              </Button>
              <Button
                onClick={() => downloadProcessAsSvg()}
                style={downStyle}
                type={"link"}>
                下载为SVG文件
              </Button>
              <Button
                onClick={() => downloadProcessAsBpmn()}
                style={downStyle}
                type={"link"}>
                下载为BPMN文件
              </Button>
            </div>
          }>
          <Button icon={<DownloadOutlined />} type={"primary"}>
            下载文件
          </Button>
        </Tooltip>
        <Divider className={styles.divider} type="vertical" />
        <Tooltip
          color={tooltipColor}
          title={
            <div>
              <Button
                onClick={() => previewProcessXML()}
                style={downStyle}
                type={"link"}>
                预览XML
              </Button>
              <Button
                onClick={() => previewProcessJson()}
                style={downStyle}
                type={"link"}>
                预览JSON
              </Button>
            </div>
          }>
          <Button icon={<EyeOutlined />} type={"primary"}>
            预览
          </Button>
        </Tooltip>
        {/* <Divider className={styles.divider} type="vertical" />
        <Tooltip color={tooltipColor} title={getTitle(simulationStatus ? '退出模拟' : '开启模拟')}>
          <Button icon={<PlaySquareOutlined />} type={"primary"} onClick={() => processSimulation()}>
            模拟
          </Button>
        </Tooltip> */}
      </Button.Group>

      <Button.Group className={styles.margin_left}>
        <Tooltip title={getTitle("缩小视图")} color={tooltipColor}>
          <Button onClick={e => processZoomOut()}>
            <ZoomOutOutlined />
          </Button>
        </Tooltip>
        <Button>{Math.floor(defaultZoom * 10 * 10) + "%"}</Button>
        <Tooltip title={getTitle("放大视图")} color={tooltipColor}>
          <Button onClick={e => processZoomIn()}>
            <ZoomInOutlined />
          </Button>
        </Tooltip>
        <Tooltip title={getTitle("重置视图并居中")} color={tooltipColor}>
          <Button onClick={e => processReZoom()}>
            <AlignCenterOutlined />
          </Button>
        </Tooltip>
      </Button.Group>

      <Button.Group className={styles.margin_left}>
        <Tooltip
          title={getTitle("撤销")}
          disabled={!revocable}
          color={tooltipColor}>
          <Button disabled={!revocable} onClick={e => processUndo()}>
            <UndoOutlined />
          </Button>
        </Tooltip>
        <Tooltip title={getTitle("恢复")} color={tooltipColor}>
          <Button disabled={!recoverable} onClick={e => processRedo()}>
            <RedoOutlined />
          </Button>
        </Tooltip>
        <Tooltip title={getTitle("重新绘制")} color={tooltipColor}>
          <Button onClick={e => processRestart()}>
            <SyncOutlined />
          </Button>
        </Tooltip>
      </Button.Group>

      {/* 上传本地文件 */}
      <input
        type="file"
        id="files"
        ref={refFile}
        className={styles.updata_file}
        accept=".xml, .bpmn"
        onChange={el => importLocalFile(el)}
      />

      <Gmodal
        title={"预览"}
        width={900}
        visible={previewModelVisible}
        footer={false}
        handleCancel={() => setPreviewModelVisible(false)}
        bodyStyle={{
          minHeight: "20vh",
          maxHeight: "48vh",
          overflow: "hidden",
          paddingBottom: 20,
          marginBottom: 20,
        }}>
        <div style={{ overflow: "auto", maxHeight: "48vh" }}>
          <Highlight language={previewType} code={previewResult} />
        </div>
      </Gmodal>
    </div>
  );
};
export default Index;
